package dao

import (
	"context"
	rentalpb "coolcar/v1/rental/api/gen/v1"
	"coolcar/v1/shared/ids"
	"coolcar/v1/shared/mgutils"
	"fmt"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

var (
	identityStatusField = mgutils.ProfileFieldName + ".identitystatus"
	photoblobidField    = "photoblobid"
)

// Mongo defines a mongo db.
type Mongo struct {
	col *mongo.Collection
}

// NewMongo creates a new mongo dao.
func NewMongo(db *mongo.Database) *Mongo {
	return &Mongo{
		col: db.Collection("profile"),
	}
}

// ProfileRecord defines the profile record in db.
type ProfileRecord struct {
	AccountID   string            `bson:"accountid"`
	Profile     *rentalpb.Profile `bson:"profile"`
	PhotoBlobID string            `bson:"photoblobid"`
}

// GetProfile gets the profile record.
func (m *Mongo) GetProfile(ctx context.Context, aid ids.AccountID) (*ProfileRecord, error) {
	filter := bson.M{
		mgutils.AccountIDFieldName: aid.String(),
	}
	res := m.col.FindOne(ctx, filter)
	if err := res.Err(); err != nil {
		return nil, err
	}
	var pr ProfileRecord
	err := res.Decode(&pr)
	if err != nil {
		return nil, fmt.Errorf("failed to decode profile record: %v", err)
	}
	return &pr, nil
}

// UpdatedProfile update a profile record.
func (m *Mongo) UpdatedProfile(ctx context.Context, aid ids.AccountID, prevStatus rentalpb.IdentityStatus, p *rentalpb.Profile) error {
	filter := bson.M{
		identityStatusField: prevStatus,
	}
	if prevStatus == rentalpb.IdentityStatus_UNSUBMITTED {
		filter = mgutils.ZeroOrDoesNotExist(identityStatusField, prevStatus)
	}
	filter[mgutils.AccountIDFieldName] = aid.String()
	update := mgutils.Set(bson.M{
		mgutils.AccountIDFieldName: aid.String(),
		mgutils.ProfileFieldName:   p,
	})
	_, err := m.col.UpdateOne(ctx, filter, update, options.Update().SetUpsert(true))
	return err
}

func (m *Mongo) UpdateProfilePhoto(ctx context.Context, aid ids.AccountID, bid ids.BlobID) error {
	filter := bson.M{
		mgutils.AccountIDFieldName: aid.String(),
	}
	update := mgutils.Set(bson.M{
		mgutils.AccountIDFieldName: aid.String(),
		photoblobidField:           bid.String(),
	})
	_, err := m.col.UpdateOne(ctx, filter, update, options.Update().SetUpsert(true))
	return err
}
